knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)

library(pheatmap)
library(RColorBrewer)

set.seed(123)

library(tidyverse)
library(caret)
library(factoextra)
library(plotly)
library(uwot)
library(ggplot2)
library(randomForest)

1. INTRODUCCIÓN

En la última década, la biología molecular ha experimentado una transformación sin precedentes gracias al desarrollo de las tecnologías de secuenciación de alto rendimiento (High-Throughput Sequencing). Estas herramientas permiten medir simultáneamente la expresión de miles de genes, generando una cantidad ingente de datos que superan la capacidad de análisis estadístico convencional. En este contexto, la Inteligencia Artificial (IA) y los algoritmos de Machine Learning se han consolidado como pilares fundamentales para la interpretación de sistemas biológicos complejos.

El presente trabajo aborda el análisis de un conjunto de datos de expresión génica compuesto por 801 muestras y 500 variables (genes). Este tipo de datos se caracteriza por el fenómeno conocido como “la maldición de la dimensionalidad” (curse of dimensionality), donde el número de variables es significativamente alto en comparación con el número de observaciones. El reto principal reside en identificar patrones biológicos significativos, conocidos como firmas moleculares, que permitan distinguir entre diferentes tipologías celulares o patologías.

2. METODOLOGÍA

Para abordar este desafío, se ha diseñado un flujo de trabajo integral que combina dos vertientes del aprendizaje automático:

  • Aprendizaje No Supervisado: Mediante técnicas de reducción de dimensionalidad y clusterización (como el Análisis de Componentes Principales y la Clusterización Jerárquica), se busca explorar la estructura intrínseca de los datos sin etiquetas previas, facilitando la visualización y el descubrimiento de grupos naturales de muestras.

  • Aprendizaje Supervisado: Utilizando modelos de clasificación (como Random Forest y SVM), se entrena al sistema para reconocer y predecir la pertenencia de una muestra a una clase específica, evaluando la robustez de los modelos mediante métricas de precisión, sensibilidad y especificidad.

A través de la implementación de estos algoritmos en el lenguaje de programación R, este informe pretende demostrar cómo la aplicación rigurosa de la estadística y el aprendizaje automático permite transformar datos genómicos brutos en conocimiento biomédico accionable, facilitando el camino hacia la medicina de precisión y el diagnóstico personalizado.

3. PREPROCESAMIENTO

El flujo de trabajo comenzó con la integración de los perfiles de expresión génica, su nomenclatura y etiquetas clínicas. Para garantizar la integridad de los datos, se aplicó un protocolo de control de calidad en etapas sucesivas: en primer lugar, se realizó un filtrado de muestras (filas) para eliminar aquellas con baja calidad técnica basadas en un exceso de valores nulos. Posteriormente, se efectuó un cribado de variables (genes), descartando aquellas con una presencia de ceros superior al 90% y aquellas con varianza nula (SD=0). Estas últimas se eliminan ya que, al ser constantes, no aportan información útil para distinguir patrones; además, su exclusión es matemáticamente necesaria para evitar errores de división por cero durante el escalado y asegurar que algoritmos como PCA o k-means se centren exclusivamente en la variabilidad biológica informativa. Finalmente, se aplicó una normalización mediante centrado y escalado sobre el set de datos depurado para estandarizar las magnitudes y permitir una comparación equitativa entre las variables restantes.

gene_expression <- read.table("gene_expression.csv",
                              sep = ";",
                              header = FALSE)

##carga de nombres de genes
column_names <- read.table("column_names.txt",
                           header = FALSE,
                           stringsAsFactors = FALSE)
##cargar las clases
classes <- read.table("classes.csv",
                      sep = ";",
                      header = FALSE,
                      stringsAsFactors = FALSE)
colnames(classes) <- c("SampleID", "Class")


#CONSTRUIR EL DATAFRAME FINAL

##Asignar nombres de genes como nombres de columnas
colnames(gene_expression) <- column_names$V1
##Asignar IDs de muestra como nombres de filas
rownames(gene_expression) <- classes$SampleID
##Añadir la clase como última columna
data <- gene_expression %>%
  mutate(Class = as.factor(classes[,2]))

DEPURADO DE DATOS

##calcular la proporcion de NA por gen
na_prop <- colMeans(is.na(data))
##eliminar genes con mas del 20% de NA
data <- data[, na_prop < 0.2] #(no se elimina ningun gen)

#IMPUTACION DE VALORES NA
##No haria falta ya que no hay ningun NA, pero en un caso real cabria hacerlo
###Aqui se estima un valor razonable para los NA usando la informacion disponible
###Se realiza con KNN (k-nearest neighbors)
##separar datos y clase ya que nunca imputamos la clase, solo los datos
x <- data[, colnames(data) != "Class"]
y <- data$Class

RECUENTO DE CEROS

# identifican filas a eliminar
zero_counts_filas <- rowSums(x == 0)
umbral_filas <- ncol(x) * 0.95  # Umbral del 95% de los genes

# Identifican muestras a eliminar
indices_filas_eliminar <- which(zero_counts_filas > umbral_filas)
nombres_muestras_eliminadas <- rownames(x)[indices_filas_eliminar]
num_filas_eliminadas <- length(indices_filas_eliminar)

cat("Muestras (filas) eliminadas (> 95% ceros):", num_filas_eliminadas, "\n")
## Muestras (filas) eliminadas (> 95% ceros): 0
zero_counts <- colSums(x == 0)
umbral_95_por_ciento <- nrow(x) * 0.95 #umbral del 95%

# Se crea un df con el numero de ceros por variable
zero_df <- data.frame(
  Variable = names(zero_counts),
  Ceros = as.numeric(zero_counts)
)


# Total de filas para el porcentaje
total_filas <- nrow(x)

variables_criticas <- zero_df %>%
  filter(Ceros > umbral_95_por_ciento) %>%
  mutate(Porcentaje = (Ceros / total_filas) * 100) %>% # Crea la columna de porcentaje
  arrange(desc(Ceros))                                 # Ordena de mayor a menor

# Visualizar la tabla
print(variables_criticas)
##   Variable Ceros Porcentaje
## 1    MIER3   801  100.00000
## 2  ZCCHC12   801  100.00000
## 3  RPL22L1   801  100.00000
## 4    RAB25   791   98.75156
## 5   ZNF425   786   98.12734
## 6  ST3GAL6   781   97.50312
# identifican variables a eliminar
nombres_variables_eliminadas_ceros <- variables_criticas$Variable
num_eliminadas <- length(nombres_variables_eliminadas_ceros)


cat("Variables (columnas) eliminadas (> 95% ceros):", num_eliminadas, "\n")
## Variables (columnas) eliminadas (> 95% ceros): 6
cat("Variables:", paste(nombres_variables_eliminadas_ceros, collapse = ", "), "\n")
## Variables: MIER3, ZCCHC12, RPL22L1, RAB25, ZNF425, ST3GAL6
x_sin_ceros <- x[, !(names(x) %in% nombres_variables_eliminadas_ceros)]

DESVIACIÓN ESTANDAR

# Variables con desviación estandar 0
# Columnas con SD = 0 que indican que son constantes

desviaciones <- apply(x_sin_ceros, 2, sd) # La función apply con margen 2 calcula la SD por columna.


columnas_a_mantener <- desviaciones > 0 # se mantienen las columnas que su desviación estándar es > 0


genes_eliminados <- sum(!columnas_a_mantener)
nombres_genes_eliminados <- colnames(x_sin_ceros)[!columnas_a_mantener]

cat("Genes (columnas) eliminados (SD = 0):", genes_eliminados, "\n")
## Genes (columnas) eliminados (SD = 0): 0
# filtro sobre el dataset original para dejar solo con los genes útiles
x_filtrado <- x_sin_ceros[, columnas_a_mantener]

NORMALIZACIÓN

##centrar y escalar
preproc_scale <- preProcess(x_filtrado, method = c("center", "scale"))
X_scaled <- predict(preproc_scale, x_filtrado)


##dataset final
data_final <- X_scaled
data_final$Class <- y

cat("Dimensiones del dataset final:", dim(data_final))
## Dimensiones del dataset final: 801 495

4. MÉTODOS NO SUPERVISADOS

4.1 Reducción de dimensionalidad

4.1.1 PCA

Se ha seleccionado PCA porque permite resumir y explorar la estructura de los datos en un conjunto de alta dimensión, como es este caso. Al mismo tiempo, el PCA es útil para explorar la estructura general de los datos, aunque no captura relaciones no lineales.

# Cálculo de componentes principales (usamos los datos ya escalados)
pca.results <- prcomp(X_scaled, center = FALSE, scale. = FALSE)

# Resultado de las componentes principales en un dataframe
pca.df <- data.frame(pca.results$x)

# Análisis de la Varianza
varianzas <- pca.results$sdev^2
total.varianza <- sum(varianzas)
varianza.explicada <- varianzas / total.varianza
varianza.acumulada <- cumsum(varianza.explicada)

# Número de componentes que explican el 70%
n.pc <- min(which(varianza.acumulada > 0.70))
print(paste("Número de PCs para el 70% de varianza:", n.pc))
## [1] "Número de PCs para el 70% de varianza: 43"
### Grafico PCA 2D

# Configuración de etiquetas dinámicas para los ejes
x_label <- paste0("PC1 (", round(varianza.explicada[1] * 100, 2), "%)")
y_label <- paste0("PC2 (", round(varianza.explicada[2] * 100, 2), "%)")

# Representación gráfica
# Usamos 'y' que definimos antes como el factor de las clases
ggplot(pca.df, aes(x = PC1, y = PC2, color = y)) + 
  geom_point(size = 3, alpha = 0.8) +
  scale_color_manual(values = c("#F8766D", "#A3A000", "#00B0F6", "#00BF7D", "#E76BF3")) +
  labs(title = 'PCA', 
      
       x = x_label, 
       y = y_label, 
       color = 'Grupo') +
  theme_classic() +
  theme(
    panel.grid.major = element_line(color = "gray90"), 
    panel.grid.minor = element_blank(),
    panel.background = element_rect(fill = "gray95"), 
    plot.title = element_text(hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(hjust = 0.5)
  )

### Gráfico PCA 3D

# Definir la etiqueta del tercer eje (PC3)
z_label <- paste0('PC3 (', round(varianza.explicada[3]*100, 2), '%)')

#  Generar el gráfico interactivo 3D
plot_ly(pca.df, 
        x = ~PC1, 
        y = ~PC2, 
        z = ~PC3, 
        color = ~y,  # Usamos 'y' que contiene tus etiquetas de Class
        colors = c("#F8766D", "#A3A000", "#00B0F6", "#00BF7D", "#E76BF3"),
        type = 'scatter3d', 
        mode = 'markers',
        marker = list(size = 4, opacity = 0.8)) %>%
  layout(title = 'PCA 3D - Types of Cancer',
         scene = list(xaxis = list(title = x_label),
                      yaxis = list(title = y_label),
                      zaxis = list(title = z_label)))

4.1.2 UMAP

Se ha implementado el algoritmo UMAP como técnica avanzada de reducción de dimensionalidad no lineal para proyectar los datos de expresión génica en un espacio bidimensional. Este método permite visualizar de forma clara y eficiente la agrupación de las muestras, preservando tanto la estructura local como las relaciones globales entre las diferentes tipologías celulares.

# Separar datos y etiquetas para UMAP
x_umap <- data_final[, colnames(data_final) != "Class"]
labels_umap <- data_final$Class

# Aplicar UMAP con parámetros ajustados
# n_neighbors: número de vecinos cercanos (20% del total de muestras)
# n_components: dimensiones de salida (2 para visualización)
# min_dist: distancia mínima entre puntos
umap_results <- umap(x_umap, 
                     n_neighbors = 0.2 * nrow(x_umap),
                     n_components = 2, 
                     min_dist = 0.1, 
                     local_connectivity = 1,
                     ret_model = TRUE, 
                     verbose = TRUE)

# Crear dataframe con resultados de UMAP
umap_df <- data.frame(umap_results$embedding)
colnames(umap_df) <- c("UMAP1", "UMAP2")

# Añadir las etiquetas para el gráfico
umap_df$Class <- labels_umap

# Visualizar resultados UMAP
ggplot(umap_df, aes(x = UMAP1, y = UMAP2, color = Class)) +
  geom_point(size = 3) +
  labs(title = "UMAP - Expresión Genética", 
       x = "UMAP1", 
       y = "UMAP2", 
       color = "Tipo") +
  theme_classic() +
  theme(panel.grid.major = element_line(color = "gray90"), 
        panel.grid.minor = element_blank(),
        panel.background = element_rect(fill = "gray95"), 
        plot.title = element_text(hjust = 0.5))

4.2 CLUSTERIZACIÓN

4.2.1 K-means

Se ha seleccionado K-means por su simplicidad y eficiencia para identificar clusters. Aunque no captura relaciones no lineales, se aplica so sobre el dataset original y sobre el espacio reducido por PCA, donde los grupos son más distinguibles.

## K-means

# n optimo de clusters
fviz_nbclust(X_scaled, kmeans, method = "wss") +
  ggtitle("Optimal number of clusters", subtitle = "") +
  theme_classic()

#A partir de $k = 4$, la curva se vuelve mucho más plana (lineal), lo que sugiere que añadir más grupos no está reduciendo la varianza interna de forma significativa.


### k-means 2D

# 1. Ejecutar K-means sobre los datos ESCALADOS
# Usamos k=5 como indicaste en tu ejemplo
set.seed(123) # Para que el resultado sea reproducible
kmeans.result <- kmeans(X_scaled, 
                        centers = 4, 
                        iter.max = 100, 
                        nstart = 25)

# 2. Visualización con fviz_cluster
# Esta función hace un PCA interno para poder mostrar los datos en 2D
fviz_cluster(kmeans.result, 
             data = X_scaled, 
             geom = "point",
             palette = c("#F8766D", "#A3A000", "#00B0F6", "#00BF7D"), 
             ellipse.type = "convex", # Encierra los grupos en polígonos
             ggtheme = theme_minimal(),
             main = "Clustering K-means (k=4)")

### K-means sobre PCA

fviz_nbclust(pca.df[,1:3], kmeans, method = "wss") +
  ggtitle("Optimal number of clusters", subtitle = "") +
  theme_classic()

#Similar al anterior, se seleccionan 4 componentes.

# 1. Ejecutar K-means sobre las primeras 3 dimensiones del PCA
# Esto agrupa las muestras según su posición en el espacio 3D visualizado

kmeans.pca <- kmeans(pca.df[, 1:3], 
                     centers = 4, 
                     nstart = 100, 
                     iter.max = 300)


# 2. Visualización 2D (Proyección de los clusters)
fviz_cluster(kmeans.pca, 
             data = pca.df[, 1:3], 
             geom = "point", 
             palette = c("#F8766D", "#A3A000", "#00B0F6", "#00BF7D"),
             ellipse.type = "convex",
             ggtheme = theme_minimal(),
             main = "K-means Clustering sobre PC1-PC3 (2D)")

# 3. Preparar los clusters para el gráfico 3D
clusters <- kmeans.pca$cluster

# 4. Visualización 3D Interactiva
plot_ly(
  x = pca.df[, 1],
  y = pca.df[, 2],
  z = pca.df[, 3],
  color = as.factor(clusters),
  colors = c("#F8766D", "#A3A000", "#00B0F6", "#00BF7D"),
  type = "scatter3d",
  mode = "markers",
  marker = list(size = 4, opacity = 0.8)
) %>%
  layout(
    title = 'Clusters K-means en Espacio PCA (3D)',
    scene = list(
      xaxis = list(title = 'PC1'),
      yaxis = list(title = 'PC2'),
      zaxis = list(title = 'PC3')
    )
  )

4.2.2 HEATMAP

Se ha implementado la clusterización jerárquica aglomerativa mediante una representación de Heatmap para explorar de forma bidimensional las relaciones de similitud entre muestras y genes. Este método permite organizar los datos en una estructura de árbol o dendrograma basada en el algoritmo de Ward, facilitando la identificación visual de patrones de co-expresión y firmas moleculares específicas que definen a cada grupo patológico.

# Calcular varianza de cada gen
varianzas <- apply(x_filtrado, 2, var)

# Seleccionar top genes más representativos

# Calculamos un ANOVA para cada gen respecto a la Clase
p_values_anova <- apply(x_filtrado, 2, function(gen) {
  res_anova <- aov(gen ~ y)
  summary(res_anova)[[1]][["Pr(>F)"]][1]
})

# Elegimos los 20 genes con el p-valor más bajo (los más significativos)
top_genes_anova <- names(sort(p_values_anova))[1:20]
matriz_anova <- x_filtrado[, top_genes_anova]


# Preparar anotaciones para mostrar las clases reales
annotation_col <- data.frame(
  Clase = y
)

rownames(annotation_col) <- rownames(matriz_anova)

colores_estilo_umap <- c("#F8766D", "#A3A000", "#00B0F6", "#00BF7D", "#E76BF3")

# Colores para las clases
ann_colors <- list(
  Clase = setNames(
    colores_estilo_umap,
    unique(y) 
  )
)

# Heatmap con clustering jerárquico (método Ward)
pheatmap(t(matriz_anova),  # Transponer: genes en filas, muestras en columnas
         scale = "none",
         clustering_method = "ward.D",
         clustering_distance_rows = "euclidean",
         clustering_distance_cols = "euclidean",
         annotation_col = annotation_col,
         annotation_colors = ann_colors,
         show_rownames = TRUE,
         show_colnames = FALSE,
         main = "Clustering Jerárquico Aglomerativo - Método Ward",
         fontsize = 10,
         border_color = NA)

5. MÉTODOS SUPERVISADOS

5.1 KNN

La elección de k-NN responde a su robustez y simplicidad como clasificador no paramétrico, siendo una técnica ideal para establecer una línea base de comparación frente a modelos más complejos. Se seleccionó por su capacidad para realizar clasificaciones basadas en la proximidad local en el espacio multidimensional, lo cual resulta especialmente efectivo tras la reducción de dimensionalidad, permitiendo al algoritmo identificar con precisión la pertenencia a una clase basándose en la similitud directa entre los perfiles de expresión de las muestras vecinas.

#IMPLEMENTACION DE KNN

# Se construye el dataset final para KNN:
# - Variables predictoras: genes escalados y filtrados (X_scaled)
# - Variable respuesta: Class

data_knn <- as.data.frame(X_scaled)
data_knn$Class <- y


# División en entrenamiento y test


set.seed(123)

# Se mantiene la proporción de clases
train_index <- createDataPartition(data_knn$Class,
                                   p = 0.8,
                                   list = FALSE)

train_data <- data_knn[train_index, ]
test_data  <- data_knn[-train_index, ]


# Entrenamiento del modelo KNN

# Se utiliza validación cruzada (10-fold CV)
# para seleccionar el valor óptimo de k

control <- trainControl(
  method = "cv",
  number = 10
)

# Se prueban distintos valores de k (solo impares)
grid_k <- expand.grid(
  k = seq(3, 21, by = 2)
)

set.seed(123)

knn_model <- train(
  Class ~ .,
  data = train_data,
  method = "knn",
  trControl = control,
  tuneGrid = grid_k
)

# Mostrar el mejor valor de k
knn_model
## k-Nearest Neighbors 
## 
## 642 samples
## 494 predictors
##   5 classes: 'AGH', 'CFB', 'CGC', 'CHC', 'HPB' 
## 
## No pre-processing
## Resampling: Cross-Validated (10 fold) 
## Summary of sample sizes: 578, 577, 578, 578, 577, 579, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa    
##    3  0.9876194  0.9837155
##    5  0.9906475  0.9876700
##    7  0.9906964  0.9877463
##    9  0.9922589  0.9897552
##   11  0.9953846  0.9939139
##   13  0.9923077  0.9898322
##   15  0.9922837  0.9898027
##   17  0.9938462  0.9918533
##   19  0.9907212  0.9877496
##   21  0.9891827  0.9856859
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 11.
#El mejor valor de K que se ha obtenido ha sido o bien k = 9, k = 11, k = 13, pero caret elige 13 (primer máximo estable)

# Evaluación del modelo

# Predicciones sobre el conjunto de test
pred_knn <- predict(knn_model, newdata = test_data)

# Matriz de confusión y métricas de evaluación
cm <- confusionMatrix(pred_knn, test_data$Class)
cm
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction AGH CFB CGC CHC HPB
##        AGH  29   0   0   0   0
##        CFB   0  60   0   0   0
##        CGC   0   0  28   0   0
##        CHC   0   0   0  27   0
##        HPB   0   0   0   0  15
## 
## Overall Statistics
##                                      
##                Accuracy : 1          
##                  95% CI : (0.9771, 1)
##     No Information Rate : 0.3774     
##     P-Value [Acc > NIR] : < 2.2e-16  
##                                      
##                   Kappa : 1          
##                                      
##  Mcnemar's Test P-Value : NA         
## 
## Statistics by Class:
## 
##                      Class: AGH Class: CFB Class: CGC Class: CHC Class: HPB
## Sensitivity              1.0000     1.0000     1.0000     1.0000    1.00000
## Specificity              1.0000     1.0000     1.0000     1.0000    1.00000
## Pos Pred Value           1.0000     1.0000     1.0000     1.0000    1.00000
## Neg Pred Value           1.0000     1.0000     1.0000     1.0000    1.00000
## Prevalence               0.1824     0.3774     0.1761     0.1698    0.09434
## Detection Rate           0.1824     0.3774     0.1761     0.1698    0.09434
## Detection Prevalence     0.1824     0.3774     0.1761     0.1698    0.09434
## Balanced Accuracy        1.0000     1.0000     1.0000     1.0000    1.00000
cm_df <- as.data.frame(cm$table)

ggplot(cm_df, aes(x = Reference, y = Prediction, fill = Freq)) +
  geom_tile(color = "white") +
  geom_text(aes(label = Freq), size = 5) +
  scale_fill_gradient(low = "white", high = "steelblue") +
  labs(title = "Matriz de confusión del clasificador KNN",
       x = "Clase real",
       y = "Clase predicha") +
  theme_minimal()

5.2 SVM

La implementación de SVM se justifica por su probada eficacia en escenarios de alta dimensionalidad y su capacidad para encontrar el hiperplano óptimo de separación entre clases complejas. Se seleccionó específicamente por su versatilidad al utilizar funciones de kernel (como el gaussiano o RBF), lo que permite al modelo capturar relaciones no lineales entre los niveles de expresión génica que otros clasificadores lineales omitirían. Además, su diseño orientado a la maximización del margen garantiza una excelente capacidad de generalización, reduciendo el riesgo de sobreajuste y permitiendo una clasificación precisa de las muestras patológicas incluso con fronteras de decisión solapadas.

# Preparar X (predictores) e y (clases)
X <- data_final[, colnames(data_final) != "Class"]
y <- as.factor(data_final$Class)

dim(X)
## [1] 801 494
length(y)
## [1] 801
# Cargar librería (partición estratificada + entrenamiento + evaluación)


# Eliminar predictores con varianza cero (evita warnings al centrar/escalar)
nzv <- nearZeroVar(X, saveMetrics = TRUE)
X <- X[, !nzv$zeroVar]

# Partición train/test estratificada
set.seed(123)
train_index <- createDataPartition(y, p = 0.80, list = FALSE)

X_train <- X[train_index, ]
X_test  <- X[-train_index, ]

y_train <- y[train_index]
y_test  <- y[-train_index]

prop.table(table(y_train))
## y_train
##        AGH        CFB        CGC        CHC        HPB 
## 0.18224299 0.37383178 0.17601246 0.16978193 0.09813084
prop.table(table(y_test))
## y_test
##        AGH        CFB        CGC        CHC        HPB 
## 0.18238994 0.37735849 0.17610063 0.16981132 0.09433962
# Control del entrenamiento: validación cruzada 10-fold
ctrl <- trainControl(
  method = "cv",
  number = 10,
  classProbs = TRUE
)

# Entrenar el modelo SVM con kernel gaussiano (RBF) -> en caret: svmRadial
set.seed(123)
svm_model <- train(
  x = X_train,
  y = y_train,
  method = "svmRadial",
  trControl = ctrl,
  preProcess = c("center", "scale"),
  metric = "Accuracy"
)

svm_model
## Support Vector Machines with Radial Basis Function Kernel 
## 
## 642 samples
## 494 predictors
##   5 classes: 'AGH', 'CFB', 'CGC', 'CHC', 'HPB' 
## 
## Pre-processing: centered (494), scaled (494) 
## Resampling: Cross-Validated (10 fold) 
## Summary of sample sizes: 578, 577, 578, 578, 577, 579, ... 
## Resampling results across tuning parameters:
## 
##   C     Accuracy   Kappa    
##   0.25  0.8411145  0.7888933
##   0.50  0.8458516  0.7952821
##   1.00  0.8427499  0.7912372
## 
## Tuning parameter 'sigma' was held constant at a value of 0.001162202
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were sigma = 0.001162202 and C = 0.5.
plot(svm_model)  # rendimiento vs hiperparámetro (C)

# Predicción en test y matriz de confusión
pred_test <- predict(svm_model, newdata = X_test)
cm <- confusionMatrix(pred_test, y_test)
cm
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction AGH CFB CGC CHC HPB
##        AGH  29   0   0   0   0
##        CFB   0  60   0   1   0
##        CGC   0   0  28  22   0
##        CHC   0   0   0   4   0
##        HPB   0   0   0   0  15
## 
## Overall Statistics
##                                          
##                Accuracy : 0.8553         
##                  95% CI : (0.7909, 0.906)
##     No Information Rate : 0.3774         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.808          
##                                          
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: AGH Class: CFB Class: CGC Class: CHC Class: HPB
## Sensitivity              1.0000     1.0000     1.0000    0.14815    1.00000
## Specificity              1.0000     0.9899     0.8321    1.00000    1.00000
## Pos Pred Value           1.0000     0.9836     0.5600    1.00000    1.00000
## Neg Pred Value           1.0000     1.0000     1.0000    0.85161    1.00000
## Prevalence               0.1824     0.3774     0.1761    0.16981    0.09434
## Detection Rate           0.1824     0.3774     0.1761    0.02516    0.09434
## Detection Prevalence     0.1824     0.3836     0.3145    0.02516    0.09434
## Balanced Accuracy        1.0000     0.9949     0.9160    0.57407    1.00000
# Extracción de métricas generales
acc   <- cm$overall["Accuracy"]
kappa <- cm$overall["Kappa"]

acc
##  Accuracy 
## 0.8553459
kappa
##     Kappa 
## 0.8080013
# Métricas por clase (sensibilidad y especificidad)
sens <- cm$byClass[, "Sensitivity"]
spec <- cm$byClass[, "Specificity"]

sens
## Class: AGH Class: CFB Class: CGC Class: CHC Class: HPB 
##  1.0000000  1.0000000  1.0000000  0.1481481  1.0000000
spec
## Class: AGH Class: CFB Class: CGC Class: CHC Class: HPB 
##  1.0000000  0.9898990  0.8320611  1.0000000  1.0000000
# F1 por clase (cálculo manual: 2 * (precision * recall) / (precision + recall))
precision <- cm$byClass[, "Pos Pred Value"]
recall    <- cm$byClass[, "Sensitivity"]

f1 <- 2 * (precision * recall) / (precision + recall)
f1[is.nan(f1)] <- NA

f1
## Class: AGH Class: CFB Class: CGC Class: CHC Class: HPB 
##  1.0000000  0.9917355  0.7179487  0.2580645  1.0000000
# F1 macro-promedio (útil en multiclase)
f1_macro <- mean(f1, na.rm = TRUE)
f1_macro
## [1] 0.7935498
#matriz de confusión a data frame
cm_df <- as.data.frame(cm$table)

ggplot(cm_df, aes(x = Reference, y = Prediction, fill = Freq)) +
  geom_tile(color = "white") +
  geom_text(aes(label = Freq), size = 5) +
  scale_fill_gradient(low = "white", high = "firebrick") +
  labs(title = "Matriz de Confusión: Clasificador SVM",
       x = "Clase Real (Referencia)",
       y = "Clase Predicha") +
  theme_minimal()

5.3 RANDOM FOREST

La elección de Random Forest se fundamenta en su capacidad para manejar la alta dimensionalidad y la complejidad no lineal de los datos de expresión génica mediante el uso de conjuntos de árboles de decisión (ensemble learning). Se seleccionó por su intrínseca robustez frente al sobreajuste y su habilidad para proporcionar una medida de la importancia de las variables, lo que permite identificar qué genes específicos contribuyen en mayor medida a la diferenciación de las clases. Además, al promediar múltiples estimaciones, este modelo ofrece una alta estabilidad y precisión en la clasificación, resultando especialmente eficaz para detectar patrones biológicos sutiles que podrían pasar desapercibidos para clasificadores individuales.

#APRENDIZAJE NO SUPERVISADO RANDOM FOREST

##division de datos (0.7 train y 0.3 test)
trainIndex <- createDataPartition(data_final$Class, p = 0.7, lis = FALSE)
train_data <- data_final[trainIndex, ]
test_data <- data_final[-trainIndex, ]

cat("Dimension de train_data:", dim(train_data), "\n")
## Dimension de train_data: 563 495
cat("Dimension de test_data:", dim(test_data), "\n")
## Dimension de test_data: 238 495
cat("Dimension de clases en train:\n")
## Dimension de clases en train:
print(table(train_data$Class))
## 
## AGH CFB CGC CHC HPB 
## 103 210  99  96  55
cat("\nDistribucion de clases en test:\n")
## 
## Distribucion de clases en test:
print(table(test_data$Class))
## 
## AGH CFB CGC CHC HPB 
##  43  90  42  40  23
#ENTRENAMIENTO DEL MODELO
##entrenar Random Forest con validacion cruzada
rf_model <- train(
  Class ~ .,
  data = train_data,
  method = "rf",
  trControl = trainControl(
    method = "cv", #validacion cruzada
    number = 5, #5 folds
    savePredictions = TRUE,
    classProbs = TRUE #para calcular curvas ROC
  ),
  ntree = 75, #numero de arboles
  importance = TRUE #calcular importancia de variables
)

print(rf_model)
## Random Forest 
## 
## 563 samples
## 494 predictors
##   5 classes: 'AGH', 'CFB', 'CGC', 'CHC', 'HPB' 
## 
## No pre-processing
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 450, 452, 449, 450, 451 
## Resampling results across tuning parameters:
## 
##   mtry  Accuracy   Kappa    
##     2   0.9875945  0.9835670
##   248   0.9787591  0.9718720
##   494   0.9734333  0.9647913
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 2.
cat("\nMejor valor de mtry:", rf_model$bestTune$mtry, "\n")
## 
## Mejor valor de mtry: 2
#PREDICCIONES
##predicciones en test_data
predictions <- predict(rf_model, test_data)
predictions
##   [1] CHC AGH CHC CFB AGH AGH CGC CFB CFB AGH CFB AGH CGC AGH CHC CGC CFB CFB
##  [19] CFB AGH AGH CFB CFB CHC CHC CFB CFB HPB AGH AGH CGC CHC CFB CFB AGH AGH
##  [37] CFB CFB CGC CFB CHC CFB CGC CFB CFB CHC CHC CGC CGC AGH AGH CGC CFB CGC
##  [55] CFB CFB CHC HPB CFB CGC CFB CGC CHC CGC CFB CGC CFB CGC CFB AGH CGC CGC
##  [73] CFB CGC CHC CFB CFB CGC CHC CHC CFB CFB CFB HPB AGH CHC CFB CFB CFB CFB
##  [91] CGC CFB CFB AGH CFB AGH CFB CHC CFB HPB CGC CGC AGH CFB AGH CFB CFB HPB
## [109] CFB CGC CFB CFB AGH CHC CFB CHC CGC CFB CHC AGH HPB CFB CFB CGC CHC CHC
## [127] HPB CFB CFB CHC CFB AGH CHC CFB CGC CFB HPB CFB AGH CGC CHC CFB AGH AGH
## [145] HPB CHC CHC CGC CHC HPB AGH CFB CHC CFB CFB CFB AGH CGC CGC CGC CFB AGH
## [163] CFB CGC CFB CFB CFB CHC CGC CGC CFB HPB CHC AGH CGC CFB AGH HPB AGH CFB
## [181] HPB CFB CHC AGH CFB HPB HPB CGC CFB HPB CFB CFB AGH CGC AGH CFB CFB HPB
## [199] AGH CFB CFB CGC AGH AGH CHC HPB HPB AGH CHC CFB CHC CGC CHC CHC CHC CFB
## [217] CFB CFB AGH CFB CHC CFB CFB CFB CFB CGC CGC AGH HPB CFB CGC AGH CHC AGH
## [235] CFB CFB CFB CGC
## Levels: AGH CFB CGC CHC HPB
predictions_prob <- predict(rf_model, test_data, type = "prob")
predictions_prob
##                   AGH        CFB        CGC        CHC        HPB
## sample_0   0.04000000 0.17333333 0.08000000 0.69333333 0.01333333
## sample_6   0.57333333 0.17333333 0.12000000 0.08000000 0.05333333
## sample_7   0.05333333 0.21333333 0.05333333 0.62666667 0.05333333
## sample_8   0.05333333 0.69333333 0.14666667 0.05333333 0.05333333
## sample_17  0.78666667 0.09333333 0.05333333 0.04000000 0.02666667
## sample_18  0.76000000 0.13333333 0.08000000 0.02666667 0.00000000
## sample_22  0.05333333 0.22666667 0.60000000 0.05333333 0.06666667
## sample_23  0.06666667 0.64000000 0.14666667 0.09333333 0.05333333
## sample_28  0.06666667 0.52000000 0.20000000 0.10666667 0.10666667
## sample_32  0.57333333 0.21333333 0.16000000 0.01333333 0.04000000
## sample_33  0.09333333 0.70666667 0.05333333 0.10666667 0.04000000
## sample_36  0.57333333 0.21333333 0.16000000 0.05333333 0.00000000
## sample_37  0.06666667 0.24000000 0.56000000 0.10666667 0.02666667
## sample_40  0.81333333 0.13333333 0.01333333 0.04000000 0.00000000
## sample_46  0.10666667 0.20000000 0.08000000 0.57333333 0.04000000
## sample_49  0.00000000 0.26666667 0.57333333 0.06666667 0.09333333
## sample_55  0.10666667 0.60000000 0.14666667 0.05333333 0.09333333
## sample_56  0.01333333 0.86666667 0.04000000 0.06666667 0.01333333
## sample_62  0.02666667 0.93333333 0.01333333 0.02666667 0.00000000
## sample_68  0.86666667 0.04000000 0.04000000 0.04000000 0.01333333
## sample_77  0.45333333 0.32000000 0.14666667 0.04000000 0.04000000
## sample_80  0.00000000 0.86666667 0.08000000 0.01333333 0.04000000
## sample_86  0.05333333 0.81333333 0.09333333 0.02666667 0.01333333
## sample_90  0.01333333 0.04000000 0.04000000 0.89333333 0.01333333
## sample_91  0.04000000 0.08000000 0.05333333 0.80000000 0.02666667
## sample_92  0.02666667 0.82666667 0.12000000 0.02666667 0.00000000
## sample_93  0.10666667 0.62666667 0.06666667 0.17333333 0.02666667
## sample_96  0.08000000 0.18666667 0.09333333 0.02666667 0.61333333
## sample_101 0.88000000 0.10666667 0.01333333 0.00000000 0.00000000
## sample_105 0.81333333 0.13333333 0.02666667 0.01333333 0.01333333
## sample_108 0.14666667 0.26666667 0.52000000 0.04000000 0.02666667
## sample_110 0.02666667 0.20000000 0.02666667 0.69333333 0.05333333
## sample_111 0.01333333 0.90666667 0.06666667 0.01333333 0.00000000
## sample_114 0.05333333 0.73333333 0.14666667 0.02666667 0.04000000
## sample_115 0.94666667 0.04000000 0.01333333 0.00000000 0.00000000
## sample_117 0.93333333 0.04000000 0.00000000 0.01333333 0.01333333
## sample_118 0.02666667 0.72000000 0.12000000 0.08000000 0.05333333
## sample_119 0.05333333 0.72000000 0.13333333 0.04000000 0.05333333
## sample_120 0.09333333 0.29333333 0.44000000 0.04000000 0.13333333
## sample_123 0.04000000 0.72000000 0.06666667 0.14666667 0.02666667
## sample_126 0.02666667 0.08000000 0.02666667 0.86666667 0.00000000
## sample_127 0.05333333 0.80000000 0.05333333 0.06666667 0.02666667
## sample_136 0.25333333 0.13333333 0.49333333 0.10666667 0.01333333
## sample_146 0.12000000 0.40000000 0.06666667 0.36000000 0.05333333
## sample_152 0.02666667 0.78666667 0.08000000 0.09333333 0.01333333
## sample_157 0.02666667 0.28000000 0.08000000 0.58666667 0.02666667
## sample_158 0.02666667 0.17333333 0.05333333 0.72000000 0.02666667
## sample_159 0.01333333 0.10666667 0.73333333 0.10666667 0.04000000
## sample_161 0.06666667 0.22666667 0.58666667 0.09333333 0.02666667
## sample_162 0.76000000 0.08000000 0.10666667 0.05333333 0.00000000
## sample_167 0.86666667 0.04000000 0.04000000 0.02666667 0.02666667
## sample_168 0.14666667 0.28000000 0.42666667 0.08000000 0.06666667
## sample_169 0.06666667 0.78666667 0.08000000 0.05333333 0.01333333
## sample_171 0.10666667 0.20000000 0.50666667 0.09333333 0.09333333
## sample_172 0.08000000 0.74666667 0.09333333 0.06666667 0.01333333
## sample_174 0.06666667 0.84000000 0.05333333 0.02666667 0.01333333
## sample_177 0.05333333 0.17333333 0.04000000 0.68000000 0.05333333
## sample_180 0.02666667 0.06666667 0.08000000 0.00000000 0.82666667
## sample_182 0.10666667 0.72000000 0.12000000 0.04000000 0.01333333
## sample_187 0.08000000 0.17333333 0.65333333 0.04000000 0.05333333
## sample_188 0.13333333 0.56000000 0.18666667 0.08000000 0.04000000
## sample_189 0.10666667 0.20000000 0.46666667 0.05333333 0.17333333
## sample_193 0.06666667 0.24000000 0.09333333 0.57333333 0.02666667
## sample_194 0.08000000 0.16000000 0.68000000 0.01333333 0.06666667
## sample_196 0.02666667 0.56000000 0.10666667 0.24000000 0.06666667
## sample_199 0.06666667 0.29333333 0.57333333 0.02666667 0.04000000
## sample_206 0.05333333 0.53333333 0.29333333 0.05333333 0.06666667
## sample_210 0.17333333 0.37333333 0.42666667 0.00000000 0.02666667
## sample_216 0.04000000 0.76000000 0.12000000 0.04000000 0.04000000
## sample_220 0.84000000 0.06666667 0.04000000 0.02666667 0.02666667
## sample_221 0.05333333 0.22666667 0.60000000 0.05333333 0.06666667
## sample_224 0.06666667 0.22666667 0.64000000 0.02666667 0.04000000
## sample_225 0.08000000 0.80000000 0.06666667 0.05333333 0.00000000
## sample_229 0.04000000 0.13333333 0.72000000 0.04000000 0.06666667
## sample_235 0.01333333 0.10666667 0.05333333 0.82666667 0.00000000
## sample_248 0.12000000 0.62666667 0.21333333 0.00000000 0.04000000
## sample_250 0.04000000 0.72000000 0.17333333 0.04000000 0.02666667
## sample_252 0.10666667 0.18666667 0.34666667 0.17333333 0.18666667
## sample_254 0.02666667 0.08000000 0.14666667 0.74666667 0.00000000
## sample_256 0.10666667 0.20000000 0.14666667 0.49333333 0.05333333
## sample_266 0.14666667 0.33333333 0.24000000 0.21333333 0.06666667
## sample_268 0.16000000 0.61333333 0.16000000 0.04000000 0.02666667
## sample_271 0.04000000 0.73333333 0.08000000 0.06666667 0.08000000
## sample_272 0.08000000 0.06666667 0.06666667 0.00000000 0.78666667
## sample_274 0.84000000 0.06666667 0.02666667 0.02666667 0.04000000
## sample_275 0.04000000 0.17333333 0.08000000 0.62666667 0.08000000
## sample_276 0.05333333 0.78666667 0.08000000 0.08000000 0.00000000
## sample_279 0.09333333 0.77333333 0.09333333 0.02666667 0.01333333
## sample_281 0.02666667 0.68000000 0.16000000 0.05333333 0.08000000
## sample_282 0.06666667 0.54666667 0.09333333 0.25333333 0.04000000
## sample_284 0.04000000 0.24000000 0.52000000 0.09333333 0.10666667
## sample_286 0.04000000 0.81333333 0.08000000 0.04000000 0.02666667
## sample_287 0.05333333 0.69333333 0.17333333 0.04000000 0.04000000
## sample_288 0.49333333 0.24000000 0.13333333 0.08000000 0.05333333
## sample_293 0.06666667 0.70666667 0.10666667 0.04000000 0.08000000
## sample_295 0.78666667 0.04000000 0.13333333 0.04000000 0.00000000
## sample_300 0.08000000 0.52000000 0.16000000 0.18666667 0.05333333
## sample_304 0.05333333 0.04000000 0.05333333 0.82666667 0.02666667
## sample_306 0.08000000 0.84000000 0.06666667 0.01333333 0.00000000
## sample_312 0.05333333 0.12000000 0.10666667 0.08000000 0.64000000
## sample_313 0.09333333 0.17333333 0.46666667 0.13333333 0.13333333
## sample_314 0.09333333 0.28000000 0.45333333 0.06666667 0.10666667
## sample_316 0.86666667 0.05333333 0.06666667 0.01333333 0.00000000
## sample_320 0.16000000 0.37333333 0.33333333 0.06666667 0.06666667
## sample_327 0.93333333 0.05333333 0.01333333 0.00000000 0.00000000
## sample_328 0.05333333 0.81333333 0.08000000 0.05333333 0.00000000
## sample_329 0.01333333 0.88000000 0.05333333 0.05333333 0.00000000
## sample_339 0.04000000 0.13333333 0.25333333 0.10666667 0.46666667
## sample_340 0.05333333 0.69333333 0.10666667 0.12000000 0.02666667
## sample_355 0.12000000 0.28000000 0.53333333 0.02666667 0.04000000
## sample_358 0.04000000 0.70666667 0.14666667 0.06666667 0.04000000
## sample_359 0.01333333 0.80000000 0.14666667 0.01333333 0.02666667
## sample_364 0.61333333 0.18666667 0.16000000 0.04000000 0.00000000
## sample_365 0.00000000 0.12000000 0.01333333 0.86666667 0.00000000
## sample_370 0.06666667 0.62666667 0.26666667 0.01333333 0.02666667
## sample_372 0.01333333 0.04000000 0.02666667 0.92000000 0.00000000
## sample_373 0.09333333 0.30666667 0.48000000 0.02666667 0.09333333
## sample_375 0.02666667 0.77333333 0.12000000 0.06666667 0.01333333
## sample_377 0.04000000 0.21333333 0.04000000 0.66666667 0.04000000
## sample_381 0.80000000 0.06666667 0.08000000 0.05333333 0.00000000
## sample_387 0.05333333 0.13333333 0.21333333 0.06666667 0.53333333
## sample_392 0.05333333 0.73333333 0.10666667 0.08000000 0.02666667
## sample_393 0.02666667 0.81333333 0.13333333 0.02666667 0.00000000
## sample_395 0.08000000 0.16000000 0.69333333 0.00000000 0.06666667
## sample_404 0.00000000 0.08000000 0.00000000 0.89333333 0.02666667
## sample_411 0.05333333 0.24000000 0.06666667 0.61333333 0.02666667
## sample_414 0.01333333 0.06666667 0.13333333 0.02666667 0.76000000
## sample_417 0.04000000 0.62666667 0.08000000 0.16000000 0.09333333
## sample_422 0.04000000 0.94666667 0.01333333 0.00000000 0.00000000
## sample_425 0.01333333 0.16000000 0.08000000 0.74666667 0.00000000
## sample_429 0.05333333 0.68000000 0.12000000 0.13333333 0.01333333
## sample_430 0.96000000 0.00000000 0.01333333 0.02666667 0.00000000
## sample_433 0.00000000 0.08000000 0.04000000 0.86666667 0.01333333
## sample_437 0.02666667 0.68000000 0.17333333 0.10666667 0.01333333
## sample_440 0.05333333 0.30666667 0.62666667 0.00000000 0.01333333
## sample_442 0.01333333 0.70666667 0.22666667 0.01333333 0.04000000
## sample_444 0.02666667 0.10666667 0.12000000 0.06666667 0.68000000
## sample_445 0.04000000 0.73333333 0.09333333 0.10666667 0.02666667
## sample_446 0.48000000 0.26666667 0.14666667 0.04000000 0.06666667
## sample_447 0.09333333 0.32000000 0.46666667 0.08000000 0.04000000
## sample_450 0.04000000 0.20000000 0.08000000 0.61333333 0.06666667
## sample_452 0.01333333 0.82666667 0.08000000 0.08000000 0.00000000
## sample_468 0.90666667 0.05333333 0.04000000 0.00000000 0.00000000
## sample_472 0.82666667 0.06666667 0.08000000 0.01333333 0.01333333
## sample_473 0.09333333 0.13333333 0.32000000 0.05333333 0.40000000
## sample_477 0.05333333 0.06666667 0.02666667 0.85333333 0.00000000
## sample_478 0.04000000 0.05333333 0.08000000 0.81333333 0.01333333
## sample_485 0.05333333 0.22666667 0.53333333 0.10666667 0.08000000
## sample_486 0.02666667 0.17333333 0.02666667 0.76000000 0.01333333
## sample_490 0.00000000 0.13333333 0.14666667 0.02666667 0.69333333
## sample_492 0.89333333 0.05333333 0.04000000 0.00000000 0.01333333
## sample_497 0.06666667 0.54666667 0.20000000 0.08000000 0.10666667
## sample_499 0.04000000 0.08000000 0.02666667 0.84000000 0.01333333
## sample_502 0.05333333 0.78666667 0.05333333 0.04000000 0.06666667
## sample_505 0.08000000 0.78666667 0.05333333 0.06666667 0.01333333
## sample_506 0.12000000 0.74666667 0.09333333 0.01333333 0.02666667
## sample_511 0.65333333 0.21333333 0.09333333 0.02666667 0.01333333
## sample_512 0.08000000 0.17333333 0.60000000 0.04000000 0.10666667
## sample_513 0.08000000 0.26666667 0.52000000 0.06666667 0.06666667
## sample_518 0.02666667 0.38666667 0.48000000 0.04000000 0.06666667
## sample_528 0.16000000 0.61333333 0.05333333 0.12000000 0.05333333
## sample_533 0.89333333 0.05333333 0.02666667 0.02666667 0.00000000
## sample_541 0.14666667 0.48000000 0.24000000 0.06666667 0.06666667
## sample_543 0.04000000 0.18666667 0.65333333 0.02666667 0.09333333
## sample_544 0.02666667 0.84000000 0.10666667 0.02666667 0.00000000
## sample_551 0.04000000 0.64000000 0.16000000 0.08000000 0.08000000
## sample_556 0.01333333 0.73333333 0.09333333 0.10666667 0.05333333
## sample_557 0.06666667 0.16000000 0.09333333 0.66666667 0.01333333
## sample_564 0.09333333 0.16000000 0.66666667 0.06666667 0.01333333
## sample_566 0.10666667 0.18666667 0.50666667 0.13333333 0.06666667
## sample_569 0.08000000 0.70666667 0.10666667 0.08000000 0.02666667
## sample_570 0.00000000 0.09333333 0.13333333 0.00000000 0.77333333
## sample_571 0.01333333 0.17333333 0.06666667 0.70666667 0.04000000
## sample_575 0.76000000 0.16000000 0.08000000 0.00000000 0.00000000
## sample_577 0.17333333 0.28000000 0.36000000 0.10666667 0.08000000
## sample_578 0.02666667 0.72000000 0.14666667 0.05333333 0.05333333
## sample_583 0.88000000 0.08000000 0.04000000 0.00000000 0.00000000
## sample_588 0.04000000 0.14666667 0.18666667 0.01333333 0.61333333
## sample_591 0.80000000 0.06666667 0.09333333 0.01333333 0.02666667
## sample_594 0.02666667 0.78666667 0.08000000 0.06666667 0.04000000
## sample_597 0.05333333 0.21333333 0.04000000 0.08000000 0.61333333
## sample_598 0.05333333 0.65333333 0.20000000 0.06666667 0.02666667
## sample_600 0.06666667 0.18666667 0.04000000 0.70666667 0.00000000
## sample_602 0.74666667 0.16000000 0.04000000 0.04000000 0.01333333
## sample_603 0.04000000 0.85333333 0.06666667 0.04000000 0.00000000
## sample_613 0.06666667 0.14666667 0.16000000 0.01333333 0.61333333
## sample_618 0.05333333 0.12000000 0.22666667 0.02666667 0.57333333
## sample_625 0.10666667 0.26666667 0.38666667 0.05333333 0.18666667
## sample_629 0.04000000 0.68000000 0.14666667 0.08000000 0.05333333
## sample_634 0.01333333 0.05333333 0.21333333 0.04000000 0.68000000
## sample_641 0.06666667 0.62666667 0.10666667 0.09333333 0.10666667
## sample_642 0.02666667 0.77333333 0.09333333 0.05333333 0.05333333
## sample_643 0.96000000 0.02666667 0.01333333 0.00000000 0.00000000
## sample_644 0.06666667 0.17333333 0.57333333 0.12000000 0.06666667
## sample_646 0.93333333 0.05333333 0.00000000 0.01333333 0.00000000
## sample_651 0.08000000 0.74666667 0.05333333 0.09333333 0.02666667
## sample_654 0.06666667 0.81333333 0.08000000 0.04000000 0.00000000
## sample_665 0.01333333 0.05333333 0.13333333 0.00000000 0.80000000
## sample_669 0.82666667 0.08000000 0.06666667 0.01333333 0.01333333
## sample_671 0.08000000 0.74666667 0.06666667 0.10666667 0.00000000
## sample_672 0.05333333 0.85333333 0.04000000 0.05333333 0.00000000
## sample_675 0.09333333 0.18666667 0.65333333 0.05333333 0.01333333
## sample_679 0.57333333 0.13333333 0.21333333 0.02666667 0.05333333
## sample_689 0.90666667 0.01333333 0.04000000 0.04000000 0.00000000
## sample_690 0.04000000 0.09333333 0.06666667 0.80000000 0.00000000
## sample_692 0.08000000 0.21333333 0.22666667 0.01333333 0.46666667
## sample_693 0.02666667 0.04000000 0.26666667 0.04000000 0.62666667
## sample_698 0.81333333 0.06666667 0.10666667 0.00000000 0.01333333
## sample_704 0.02666667 0.05333333 0.04000000 0.86666667 0.01333333
## sample_705 0.02666667 0.84000000 0.06666667 0.05333333 0.01333333
## sample_707 0.08000000 0.24000000 0.08000000 0.60000000 0.00000000
## sample_713 0.16000000 0.21333333 0.32000000 0.13333333 0.17333333
## sample_714 0.00000000 0.02666667 0.01333333 0.96000000 0.00000000
## sample_715 0.05333333 0.14666667 0.12000000 0.65333333 0.02666667
## sample_717 0.09333333 0.20000000 0.04000000 0.64000000 0.02666667
## sample_719 0.09333333 0.81333333 0.04000000 0.02666667 0.02666667
## sample_722 0.08000000 0.65333333 0.21333333 0.04000000 0.01333333
## sample_723 0.08000000 0.53333333 0.14666667 0.16000000 0.08000000
## sample_724 0.78666667 0.08000000 0.10666667 0.01333333 0.01333333
## sample_725 0.10666667 0.72000000 0.06666667 0.09333333 0.01333333
## sample_731 0.04000000 0.29333333 0.02666667 0.64000000 0.00000000
## sample_746 0.04000000 0.84000000 0.08000000 0.01333333 0.02666667
## sample_750 0.04000000 0.72000000 0.17333333 0.01333333 0.05333333
## sample_753 0.02666667 0.82666667 0.01333333 0.09333333 0.04000000
## sample_757 0.05333333 0.64000000 0.13333333 0.16000000 0.01333333
## sample_759 0.09333333 0.30666667 0.49333333 0.05333333 0.05333333
## sample_761 0.05333333 0.24000000 0.65333333 0.02666667 0.02666667
## sample_765 0.92000000 0.02666667 0.02666667 0.01333333 0.01333333
## sample_767 0.05333333 0.12000000 0.34666667 0.06666667 0.41333333
## sample_772 0.06666667 0.68000000 0.16000000 0.09333333 0.00000000
## sample_776 0.09333333 0.21333333 0.60000000 0.01333333 0.08000000
## sample_781 0.93333333 0.05333333 0.01333333 0.00000000 0.00000000
## sample_788 0.05333333 0.21333333 0.06666667 0.64000000 0.02666667
## sample_789 0.41333333 0.17333333 0.12000000 0.20000000 0.09333333
## sample_791 0.02666667 0.82666667 0.10666667 0.02666667 0.01333333
## sample_793 0.02666667 0.82666667 0.04000000 0.08000000 0.02666667
## sample_796 0.02666667 0.77333333 0.08000000 0.10666667 0.01333333
## sample_798 0.20000000 0.21333333 0.22666667 0.20000000 0.16000000
#METRICAS DE EVALUACION
##matriz de confusion
conf_matrix <- confusionMatrix(predictions, test_data$Class)
print(conf_matrix)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction AGH CFB CGC CHC HPB
##        AGH  43   0   0   0   0
##        CFB   0  90   2   1   0
##        CGC   0   0  40   0   3
##        CHC   0   0   0  39   0
##        HPB   0   0   0   0  20
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9748          
##                  95% CI : (0.9459, 0.9907)
##     No Information Rate : 0.3782          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9665          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: AGH Class: CFB Class: CGC Class: CHC Class: HPB
## Sensitivity              1.0000     1.0000     0.9524     0.9750    0.86957
## Specificity              1.0000     0.9797     0.9847     1.0000    1.00000
## Pos Pred Value           1.0000     0.9677     0.9302     1.0000    1.00000
## Neg Pred Value           1.0000     1.0000     0.9897     0.9950    0.98624
## Prevalence               0.1807     0.3782     0.1765     0.1681    0.09664
## Detection Rate           0.1807     0.3782     0.1681     0.1639    0.08403
## Detection Prevalence     0.1807     0.3908     0.1807     0.1639    0.08403
## Balanced Accuracy        1.0000     0.9899     0.9685     0.9875    0.93478
##extraer metricas clave
cat("Accuracy:", round(conf_matrix$overall['Accuracy'], 4), "\n")
## Accuracy: 0.9748
cat("\nMétricas por clase:\n")
## 
## Métricas por clase:
print(conf_matrix$byClass[, c('Sensitivity', 'Specificity', 'Precision', 'F1')])
##            Sensitivity Specificity Precision        F1
## Class: AGH   1.0000000   1.0000000 1.0000000 1.0000000
## Class: CFB   1.0000000   0.9797297 0.9677419 0.9836066
## Class: CGC   0.9523810   0.9846939 0.9302326 0.9411765
## Class: CHC   0.9750000   1.0000000 1.0000000 0.9873418
## Class: HPB   0.8695652   1.0000000 1.0000000 0.9302326
#metricas promedio
cat("\nMétricas promedio (macro):\n")
## 
## Métricas promedio (macro):
cat("Sensitivity promedio:", round(mean(conf_matrix$byClass[,'Sensitivity'], na.rm=TRUE), 4), "\n")
## Sensitivity promedio: 0.9594
cat("Specificity promedio:", round(mean(conf_matrix$byClass[,'Specificity'], na.rm=TRUE), 4), "\n")
## Specificity promedio: 0.9929
cat("F1-Score promedio:", round(mean(conf_matrix$byClass[,'F1'], na.rm=TRUE), 4), "\n")
## F1-Score promedio: 0.9685
#IMPORTANCIA DE VARIABLES (GENES)
importance <- varImp(rf_model, scale = FALSE)
cat("\nTop 20 genes mas importances:\n")
## 
## Top 20 genes mas importances:
print(head(importance$importance, 20))
##                AGH         CFB        CGC         CHC        HPB
## DUOXA1   0.0000000  0.67648541  0.6096191  1.00673408  1.4319365
## INTU     1.9357716  0.87785194  1.6992477  1.00673408  1.0067341
## UMOD    -1.0067341  1.60097127  1.0067341 -1.00673408  1.3840127
## STXBP4   0.3971151  1.76411716  0.4757189 -0.17636333  1.6550606
## PARN    -0.5625987  1.47617882  1.0403297  1.00673408  1.7918403
## TSC22D4  0.7104175  1.09596896  2.6049686  1.79058514 -1.0067341
## TTLL5    1.0067341 -0.39946773  1.6860087  0.01885455  1.1853508
## ZNF880   0.0000000  1.81531738  0.3577852 -0.34960050  1.0067341
## SPATA1   1.0067341  0.60524281  1.4195434  0.00000000  1.3737103
## PLIN3   -0.8912558 -0.05299675  0.0000000 -1.00673408 -1.0067341
## AKAP12   1.6449604  1.53130834 -1.0067341  0.00000000  0.6654774
## USP48    0.8457391  1.75145879 -0.6596156  0.00000000  1.8119018
## UBR4     1.0067341  0.08504353  1.0067341  0.37651460  1.7022273
## CCDC92   1.1588943  1.94633649  0.8224452  1.70107320  2.0032985
## ATP5MK   1.3829303 -1.31617958 -0.3222880  1.81837429  1.4905585
## VEGFD    1.7600795  1.75797444  0.7863866  1.82594107  2.0078909
## DDX42    1.5502571  1.64979017  0.4112477  1.23166555  1.3704226
## CASKIN2  1.5963538  1.78629366 -0.5390546  1.55132854 -0.7370182
## OR10P1  -1.0067341  1.43097924  1.7090619  1.36844632  0.0000000
## SHC1     0.8862603  1.19253217 -1.6628218  1.71358703  0.1712302
##visualizacion de importancia
pdf("random_forest_importance.pdf", width = 10, height = 8)
plot(importance, top = 20, main = "Top 20 genes mas importances")
dev.off()
## png 
##   2
cat("\nGrafico guardado en: random_forest_importance.pdf\n")
## 
## Grafico guardado en: random_forest_importance.pdf
#ANALISIS DE ERRORES
##Identificar muestras mal clasificadas
errors <- which(predictions != test_data$Class)
cat("Numero de muestras mal clasificadas:", length(errors), "\n")
## Numero de muestras mal clasificadas: 6
cat("Porcentaje de error:", round(length(errors)/nrow(test_data)*100, 2), "%\n")
## Porcentaje de error: 2.52 %
if(length(errors) > 0 && length(errors) <= 10) {
  cat("\nMuestras mal clasificadas:\n")
  error_df <- data.frame(
    Muestra = rownames(test_data)[errors],
    Clase_Real = test_data$Class[errors],
    Prediccion = predictions[errors]
  )
  print(error_df)
}
## 
## Muestras mal clasificadas:
##      Muestra Clase_Real Prediccion
## 1 sample_146        CHC        CFB
## 2 sample_252        HPB        CGC
## 3 sample_266        CGC        CFB
## 4 sample_320        CGC        CFB
## 5 sample_713        HPB        CGC
## 6 sample_798        HPB        CGC
cm_rf_df <- as.data.frame(conf_matrix$table)

ggplot(cm_rf_df, aes(x = Reference, y = Prediction, fill = Freq)) +
  geom_tile(color = "white") +
  geom_text(aes(label = Freq), size = 5) +
  scale_fill_gradient(low = "white", high = "darkgreen") + # Color verde para variar del SVM
  labs(title = "Matriz de Confusión: Random Forest",
       x = "Clase Real (Referencia)",
       y = "Clase Predicha") +
  theme_minimal()

6. RESPUESTA A LAS PREGUNTAS

6.1 Procesamiento de los datos

6.1.1 ¿Qué método habéis escogido para llevar a cabo la imputación de los datos?

En el flujo de preprocesamiento se evaluó primero la presencia de valores perdidos (NA) por gen. Tras aplicar el filtrado por proporción de NA (umbral < 20%), se comprobó que en el conjunto de datos final no existían valores NA, por lo que no fue necesaria una imputación efectiva para continuar con los análisis.

Aun así, se consideró como método idóneo para un caso real la imputación mediante KNN (K-Nearest Neighbors), ya que en datos de expresión génica resulta ventajoso imputar utilizando la similitud multivariante entre muestras. Este enfoque preserva mejor las correlaciones y patrones de coexpresión que métodos más simples como media/mediana, que podrían distorsionar la estructura biológica del dataset.

6.1.2 ¿Habéis llevado a cabo algún otro tipo de procesamiento?

Sí. Se implementaron varios pasos adicionales importantes para mejorar la calidad del dataset y optimizar el rendimiento de los algoritmos:

Filtrado de muestras con exceso de ceros: se eliminaron muestras con más del 95% de genes con valor 0, ya que este patrón suele asociarse a baja calidad técnica o perfiles poco informativos.

Filtrado de genes con exceso de ceros: se eliminaron genes con más del 95% de ceros en las muestras, dado que aportan escasa señal biológica y tienden a introducir ruido en análisis posteriores.

Eliminación de genes constantes (SD = 0): se descartaron variables sin variabilidad, ya que no contribuyen a discriminar entre clases y además pueden generar problemas matemáticos en la normalización (divisiones por cero).

Normalización (centrado y escalado): se aplicó estandarización tipo z-score para asegurar que todos los genes contribuyen de forma comparable, especialmente en técnicas sensibles a escala como PCA, UMAP, KNN y SVM.

Estos pasos permiten reducir ruido, eliminar redundancia y hacer el conjunto de datos más estable para modelado. ## 6.2 Métodos no supervisados

6.2.1 ¿Por qué se seleccionaron estas técnicas de reducción de dimensionalidad?

Se eligió PCA debido a la alta complejidad y dimensionalidad del dataset original (como demuestra el hecho de necesitar 43 componentes para alcanzar el 70% de la varianza). El objetivo principal era simplificar la estructura de los datos sin perder la información esencial, permitiendo identificar patrones globales y tendencias generales que a simple vista son invisibles. Además, se utilizó como paso previo para mejorar la eficiencia de otros algoritmos, eliminando el ruido y la redundancia entre variables correlacionadas.

Se seleccionó UMAP dada su excepcional capacidad para preservar tanto la estructura local como la global en datasets de alta dimensionalidad, permitiendo identificar no solo qué muestras son similares entre sí, sino también cómo se relacionan los grandes grupos biológicos. A diferencia de métodos lineales como el PCA, UMAP gestiona eficazmente las relaciones no lineales intrínsecas en los datos de expresión génica, ‘comprimiendo’ miles de dimensiones en un espacio bidimensional sin sacrificar la topología de los datos. Además, esta técnica mejora significativamente la separabilidad de las clases, facilitando la tarea posterior de algoritmos supervisados como las máquinas de vectores de soporte (SVM) al generar límites de decisión mucho más definidos y compactos.

6.2.2 ¿Por qué se seleccionaron estas técnicas de clusterización?

La elección de K-means responde a su equilibrio entre eficacia y coste computacional. Es una técnica ideal para establecer una base de segmentación rápida, especialmente útil cuando se trabaja tanto sobre el dataset completo como sobre las dimensiones proyectadas por el PCA. Se seleccionó por su capacidad para realizar una partición directa del espacio, facilitando la interpretación de los grupos formados en función de su cercanía a los centroides.

La elección de la clusterización jerárquica aglomerativa (Heatmap) responde a su capacidad para integrar en una sola visualización la estructura jerárquica de los datos y los perfiles de expresión génica. Es una técnica ideal para identificar patrones de co-expresión y firmas moleculares complejas, permitiendo explorar las relaciones de similitud en múltiples niveles sin la restricción de prefijar un número de grupos. Se seleccionó por su potencia para el análisis exploratorio bidimensional, facilitando la interpretación biológica de los clústeres al revelar visualmente qué genes específicos son responsables de la diferenciación entre las distintas clases de muestras.

6.2.3. Aspectos positivos y negativos de cada una

  • PCA:
    • Positivo: Excelente para comprimir información y facilitar la visualización de grandes volúmenes de datos. Ayuda a evitar el overfitting al reducir el número de variables.
    • Negativo: Tiene una naturaleza lineal, lo que significa que si existen relaciones complejas o curvas en los datos (no lineales), el PCA no podrá capturarlas adecuadamente.
  • UMAP:
    • Positivo:
      • Conservación de la topología: A diferencia de t-SNE, UMAP suele mantener mejor las distancias entre clústeres lejanos. Por ejemplo, en tu gráfico, la distancia de AGH al resto tiene un significado biológico real de diferenciación.
      • Escalabilidad y Velocidad: Es computacionalmente más eficiente que otros algoritmos no lineales, lo que permite procesar grandes matrices de expresión génica rápidamente.
      • Claridad Visual: Genera agrupamientos muy definidos, lo que ayuda a identificar subtipos celulares o estados patológicos de forma intuitiva.
    • Negativo:
      • Sensibilidad a Hiperparámetros: la elección de n_neighbors (vecinos) y min_dist (distancia mínima) cambia drásticamente el resultado.
      • Un “n_neighbors” bajo se enfoca en detalles muy pequeños.
      • Un “n_neighbors” alto prioriza la visión general.
      • Interpretación de los ejes: Los ejes UMAP1 y UMAP2 no tienen una unidad física ni una magnitud biológica directa (como sí la tienen los Componentes Principales en un PCA). Son unidades abstractas.
      • Naturaleza Estocástica: Si no se fija una “semilla” (seed), el gráfico puede variar ligeramente cada vez que se ejecuta, lo que puede afectar la reproducibilidad si no se es cuidadoso.
  • K-means:
    • Positivo: Es extremadamente rápido y escalable. Su implementación es intuitiva y permite asignar etiquetas de grupo de manera inmediata a cada observación.

    • Negativo: Es muy vulnerable a los valores atípicos y obliga a definir de antemano el número de clústeres , lo cual no siempre es evidente. Además, asume que los grupos tienen formas esféricas, lo que no siempre ocurre en la realidad.

  • Heatmap
    • Positivos:
      • Jerarquía visual: Gracias al dendrograma, podemos ver no solo que dos muestras son parecidas, sino qué tan parecidas son en relación con el resto del dataset sin prefijar el número de grupos (a diferencia de K-means).
      • Robustez: Como bien dicen tus apuntes, Ward es más resistente a valores atípicos (outliers) porque su métrica se basa en la suma de cuadrados, lo que suaviza el impacto de ruidos puntuales en la medición de un gen.
      • Interpretación Dual: Es la única técnica que permite ver el “porqué” de un clúster: podemos señalar exactamente qué genes están “en rojo” (sobreexpresados) para justificar la agrupación de una muestra.
    • Negativos:
      • Coste Computacional: Al calcular una matriz de distancias completa (N×N), si el dataset fuera de millones de muestras en lugar de 801, el ordenador se quedaría sin memoria. *Inestabilidad (Sensibilidad): Si eliminamos algunas muestras de una clase (ej. 10 muestras de BRCA), el árbol jerárquico podría reestructurarse de forma distinta, lo que complica la replicabilidad exacta en otros estudios.
      • Subjetividad: La elección de la distancia (Euclídea) y el linkage (Ward) es una decisión del investigador; otro analista podría usar distancia Manhattan y obtener grupos diferentes.

6.2.4. En la clusterización, ¿podéis afirmar con certeza que los clústeres generados son los mejores posibles?

No se puede afirmar con certeza absoluta que los clústeres generados sean los mejores posibles, ya que la clusterización es un proceso de aprendizaje no supervisado donde el resultado óptimo es dependiente de la métrica y el algoritmo utilizado. Esta incertidumbre se confirma al contrastar los resultados de K-means con la clusterización jerárquica del Heatmap, donde se observa un solapamiento significativo y una falta de fronteras nítidas entre grupos específicos (como CFB, CGC, CHC y HPB), indicando que sus perfiles de expresión son altamente similares. Mientras que K-means puede converger en mínimos locales debido a la disposición inicial de los centroides, la estructura jerárquica del Heatmap revela que, aunque existen tendencias globales claras, la alta dimensionalidad y la naturaleza no lineal de los datos sugieren la existencia de agrupaciones más óptimas que las métricas de distancia tradicionales no logran capturar con total precisión.

6.3 Métodos supervisados

6.3.1 ¿Cuál es el motivo por el cual habéis seleccionado ambas técnicas de aprendizaje supervisado?

Se seleccionaron KNN, SVM y Random Forest por ser modelos adecuados y complementarios para clasificación con datos de expresión génica:

KNN permite comparar muestras por proximidad en el espacio de genes. Es sencillo y útil como baseline, aunque requiere escalado y puede verse afectado por alta dimensionalidad.

SVM (kernel radial/RBF) es especialmente eficaz en alta dimensionalidad y permite fronteras de decisión no lineales, lo que encaja muy bien con perfiles genómicos complejos.

Random Forest ofrece alta robustez frente a ruido, suele generalizar bien y además permite extraer importancia de variables (genes), aportando valor interpretativo.

6.3.2 ¿Cuál ha dado mejores resultados a la hora de clasificar las muestras?

Tras analizar los resultados de las matrices de confusión, el modelo KNN es el que presenta el mejor desempeño, logrando una exactitud (Accuracy) del 100% y un índice Kappa de 1.0. Este modelo clasificó correctamente la totalidad de las muestras, mostrando una sensibilidad y especificidad perfectas en todas las categorías.

En segundo lugar, el modelo Random Forest (RF) mostró también un buen rendimiento con una precisión del 97.48%, cometiendo únicamente errores marginales en la distinción de las clases CGC y HPB. Por el contrario, el modelo SVM resultó ser el menos eficaz, aunque su precisión global es del 85.53%, presenta un fallo crítico en la clase CHC, donde su sensibilidad cae drásticamente al 14.8%, lo que indica una incapacidad casi total para identificar correctamente dicha categoría en comparación con los otros dos algoritmos.

6.3.3 ¿Habéis considerado oportuno implementar algún método de reducción de dimensionalidad para procesar los datos antes de implementarlos en dichas técnicas? ¿Por qué?

Sí, se consideró la posibilidad de aplicar métodos de reducción de dimensionalidad como PCA o UMAP antes del entrenamiento de los modelos supervisados, debido a la alta dimensionalidad del dataset de expresión génica. Sin embargo, se decidió no aplicar estas técnicas en el bloque supervisado, y trabajar directamente sobre el espacio original de genes tras un preprocesamiento riguroso.

Los modelos empleados (SVM con kernel radial y Random Forest) están específicamente diseñados para manejar espacios de alta dimensionalidad y relaciones no lineales, por lo que no requieren necesariamente una reducción previa de dimensiones para funcionar de manera eficaz. Además, en el caso de Random Forest, mantener los genes originales es fundamental para poder interpretar la importancia de las variables y extraer conclusiones biológicas.

Por último, los métodos de reducción de dimensionalidad se reservaron para el bloque no supervisado con un objetivo principalmente exploratorio y de visualización (PCA y UMAP), mientras que en el aprendizaje supervisado se priorizó la preservación de la información original para maximizar la capacidad predictiva y la interpretabilidad de los modelos.

6.3.4 ¿Qué aspectos positivos y negativos tienen cada una de las técnicas que habéis escogido?

Cada técnica supervisada presenta ventajas y limitaciones en este problema de clasificación con datos de expresión génica. En primer lugar, el clasificador KNN destaca por su sencillez y por ser un método intuitivo, ya que basa la predicción en la similitud con las muestras más cercanas. Esto puede ser útil cuando las clases presentan patrones de vecindad claros. Sin embargo, su rendimiento puede verse afectado por la alta dimensionalidad del dataset (maldición de la dimensionalidad), además de ser sensible a la escala de las variables (por lo que requiere normalización) y a la elección del parámetro k, que condiciona notablemente el resultado final.

Por otro lado, las máquinas de vectores de soporte (SVM), especialmente con kernel radial, son muy adecuadas para datos con gran número de variables como los de expresión génica. Este método puede generar fronteras de decisión no lineales, lo que permite capturar patrones complejos y generalmente proporciona un buen rendimiento y capacidad de generalización. Como limitación, SVM suele requerir un ajuste cuidadoso de hiperparámetros y puede tener un mayor coste computacional, especialmente cuando se trabaja con conjuntos de datos de alta dimensión.

Finalmente, Random Forest es un modelo robusto y flexible, capaz de manejar relaciones no lineales y de generalizar bien al combinar múltiples árboles de decisión. Una ventaja muy relevante en el contexto biológico es que permite obtener estimaciones de importancia de variables, lo que facilita identificar genes que contribuyen más a la clasificación. Como inconveniente, su interpretabilidad global es inferior a modelos más simples, y el rendimiento puede depender del ajuste de parámetros como el número de árboles o el número de variables evaluadas en cada partición.

6.4 De estas cuatro opciones, ¿qué tipo de arquitectura de deep learning sería la más adecuada para procesar datos de expresión génica?

En el caso de los datos de expresión génica utilizados en esta práctica, donde cada muestra se representa como un vector de valores numéricos correspondiente a la expresión de distintos genes, la arquitectura de deep learning más adecuada sería una red neuronal multicapa tipo perceptrón (MLP). Esto se debe a que el dataset tiene una estructura tabular, sin organización espacial como en imágenes ni dependencias secuenciales explícitas como en series temporales. Por tanto, una red MLP se adapta de forma directa a este tipo de entradas y permite modelar relaciones complejas entre genes mediante capas densas.

En comparación, las redes convolucionales suelen ser más apropiadas cuando existe una estructura espacial local (como sucede en imágenes), las redes recurrentes se utilizan principalmente para datos secuenciales o temporales, y las redes de grafos serían especialmente útiles si los datos estuvieran formulados explícitamente como una red biológica (por ejemplo, una red regulatoria gen-gén), lo cual no corresponde con la representación proporcionada en esta práctica.

a)  Red de perceptrones (multiperceptron layers).

La arquitectura más adecuada para procesar datos de expresión génica en este caso sería una red de perceptrones multicapa (MLP), porque este tipo de datos se representa como una tabla de valores numéricos donde cada muestra es un vector de expresión (genes como variables). Es decir, no existe estructura espacial como en imágenes (donde tendría sentido una CNN), ni una dependencia temporal/secuencial clara como en textos o series temporales (donde se usarían RNN). Por ello, una MLP es el enfoque más natural y directo para aprender patrones complejos a partir de variables tabulares de alta dimensionalidad como los genes.

    b)  Redes convolucionales.

 

    c)  Redes recurrentes.


    d)  Redes de grafos.